package com.yaosheng.thread.lock;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by yaosheng on 2021/7/1.
 */
public class TestReentrantLock<T> {

    private final LinkedList<T> lists = new LinkedList<> ();
    private final int MAX = 10;   //最大10个元素
    private int count = 0;

    private Lock lock = new ReentrantLock ();
    private Condition producer = lock.newCondition ();
    private Condition consumer = lock.newCondition ();

    public synchronized void put(T t){

        try {
            lock.lock ();
            while (lists.size () == MAX) {
                producer.await ();
            }
            lists.add (t);
            count++;
            consumer.signalAll ();   //通知消费者线程进行消费
        }catch (InterruptedException e){
            e.printStackTrace ();
        }finally {
            lock.unlock ();
        }
    }

    public synchronized T get(){

        T t = null;
        try {
            lock.lock ();
            while (lists.size () == MAX) {
                producer.await ();
            }
            t = lists.removeFirst ();
            count --;
            producer.signalAll ();   //通知生产者线程进行生产
        }catch (InterruptedException e){
            e.printStackTrace ();
        }finally {
            lock.unlock ();
        }
        return t;
    }

    public static void main(String[] args) {

        TestSynchronized<String> testSynchronized = new TestSynchronized<> ();

        //启动消费者线程
        for(int i = 0;i < 10;i ++){
            new Thread ( () -> {
                for(int j = 0; j < 5;j ++) System.out.println (testSynchronized.get ());
            },"c" + i).start ();

            try{
                TimeUnit.SECONDS.sleep (2);
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
        }

        //启动生产者线程
        for(int i = 0;i < 2;i ++){
            new Thread ( () -> {
                for(int j = 0;j < 25;j ++) testSynchronized.put (Thread.currentThread ().getName () + " " + j);
            },"p" + i).start ();
        }
    }
}
